<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch, computed, defineProps } from 'vue'
import { showToast, showDialog, Icon } from 'vant'
import { useChatStore } from '@/store/chat'
import 'highlight.js/styles/github.css'
import ReferenceMaterial from './components/ReferenceMaterial.vue'
import SearchInput from './components/SearchInput.vue'
import MessageList from './components/MessageList.vue'
import WelcomeMessage from './components/WelcomeMessage.vue'

type MessageType = {
  type: 'user' | 'ai';
  content: string;
} & (
  | { 
      hasThinking: true;
      thinking: {
        content: string;
        done: boolean;
        time: number;
        startTime?: number;
      };
      hasReferences?: boolean;
      references?: any[];
      referenceCount?: number;
    }
  | {
      hasThinking?: false;
      thinking?: undefined;
      hasReferences?: boolean;
      references?: any[];
      referenceCount?: number;
    }
);

const chatStore = useChatStore()

const historyMessages = ref<MessageType[]>([])

const sessionId = ref('')
const message = computed(() => chatStore.connectionState.searchMessage)
const loading = computed(() => chatStore.connectionState.searchLoading)
const error = computed(() => chatStore.connectionState.error)

const props = defineProps({
  embed: { type: Boolean, default: false }
})

const initSession = () => {
  if (chatStore.currentSearchSessionId) {
    sessionId.value = chatStore.currentSearchSessionId
    const savedMessages = chatStore.getCurrentSearchMessages()
    if (savedMessages && savedMessages.length > 0) {
      historyMessages.value = savedMessages
    }
  } else {
    sessionId.value = chatStore.generateSessionId()
    chatStore.currentSearchSessionId = sessionId.value
  }
}

initSession()

const handleSearch = async (searchData: { text: string; model?: string } | string) => {
  // 处理兼容性，支持旧的字符串格式和新的对象格式
  const searchText = typeof searchData === 'string' ? searchData : searchData.text
  const model = typeof searchData === 'object' ? searchData.model : undefined
  
  historyMessages.value.push({
    type: 'user',
    content: searchText
  } as MessageType)
  
  // 创建AI消息，初始状态不包含参考资料
  const aiMessage: MessageType = {
    type: 'ai',
    content: '',
    hasThinking: false,
    hasReferences: false,
    references: [],
    referenceCount: 0
  }
  historyMessages.value.push(aiMessage)
  
  // 调用sendSearchMessage，传入回调函数来接收参考资料
  chatStore.sendSearchMessage(sessionId.value, searchText, model, (references: any[]) => {
    // 更新最后一条AI消息的参考资料信息
    const lastIndex = historyMessages.value.length - 1;
    if (lastIndex >= 0 && historyMessages.value[lastIndex].type === 'ai') {
      historyMessages.value[lastIndex].hasReferences = true;
      historyMessages.value[lastIndex].references = references;
      historyMessages.value[lastIndex].referenceCount = references.length;
      
      // 保存更新后的消息
      chatStore.saveSearchMessages(sessionId.value, historyMessages.value);
    }
  })
  
  scrollToBottom()
  shouldAutoScroll.value = true
  
  chatStore.saveSearchMessages(sessionId.value, historyMessages.value)
}

const handleStopStream = () => {
  chatStore.stopStream('search')
  
  const lastIndex = historyMessages.value.length - 1
  if (lastIndex >= 0 && historyMessages.value[lastIndex].type === 'ai') {
    const lastAIMessage = historyMessages.value[lastIndex]
    
    if (lastAIMessage.hasThinking && lastAIMessage.thinking) {
      const thinkingMessage = lastAIMessage as Extract<MessageType, { hasThinking: true }>;
      thinkingMessage.thinking.done = true;
      
      if (!thinkingMessage.thinking.time || thinkingMessage.thinking.time <= 0) {
        if (thinkingMessage.thinking.startTime) {
          const elapsedTime = Date.now() - thinkingMessage.thinking.startTime;
          thinkingMessage.thinking.time = Math.max(1, Math.round(elapsedTime / 1000));
        } else {
          thinkingMessage.thinking.time = 1;
        }
      }
    }
    
    if (!lastAIMessage.content && (!lastAIMessage.hasThinking || 
        (lastAIMessage.hasThinking && !lastAIMessage.thinking?.content))) {
      lastAIMessage.content = '回答已中断'
    }
  }
}

const clearHistory = () => {
  showDialog({
    title: '清空确认',
    message: '确定要清空当前会话的所有消息吗？',
    showCancelButton: true,
    cancelButtonText: '取消',
    confirmButtonText: '确定',
    confirmButtonColor: '#4080ff',
  }).then(() => {
    if (loading.value) {
      handleStopStream()
    }
    
    historyMessages.value = []
    chatStore.clearSearchMessage()
    
    chatStore.clearSearchMessages(sessionId.value)
    
    sessionId.value = chatStore.generateSessionId()
    chatStore.currentSearchSessionId = sessionId.value
    
    showToast('会话已清空')
  }).catch(() => {})
}

const shouldAutoScroll = ref(true)
const isUserScrolling = ref(false)
const scrollTimer = ref<ReturnType<typeof setTimeout> | null>(null)
const chatContent = ref<HTMLDivElement>()

const scrollToBottom = () => {
  requestAnimationFrame(() => {
    if (chatContent.value) {
      chatContent.value.scrollTo({
        top: chatContent.value.scrollHeight,
        behavior: 'auto'
      });
    }
  });
}

const isScrolledToBottom = (): boolean => {
  if (!chatContent.value) return true
  
  const { scrollTop, scrollHeight, clientHeight } = chatContent.value
  return scrollHeight - scrollTop - clientHeight < 20
}

const handleScroll = () => {
  if (scrollTimer.value) {
    clearTimeout(scrollTimer.value)
  }
  isUserScrolling.value = true
  shouldAutoScroll.value = isScrolledToBottom()
  scrollTimer.value = setTimeout(() => {
    isUserScrolling.value = false
  }, 150)
}

const parseAIMessage = (msg: string) => {
  const result = {
    content: '',
    thinking: '',
    thinkingDone: false
  }
  
  try {
    console.log('msg', msg);
    let originalMsg = msg;
    
    // 使用正则表达式找到完整的<think></think>标签对
    const thinkTagRegex = /<think>([\s\S]*?)<\/think>/;
    const thinkTagMatch = originalMsg.match(thinkTagRegex);
    
    // 检查是否有完整的思考标签对
    if (thinkTagMatch) {
      // 有完整的标签对
      result.thinking = thinkTagMatch[1].trim();
      result.thinkingDone = true;
      // 移除完整的思考标签及其内容
      originalMsg = originalMsg.replace(thinkTagRegex, '');
    } else {
      // 没有完整的标签对，检查是否有开始标签
      const thinkOpenIndex = originalMsg.indexOf('<think>');
      
      if (thinkOpenIndex !== -1) {
        // 有开始标签，提取开始标签之后的所有内容作为思考内容
        result.thinking = originalMsg.substring(thinkOpenIndex + 7).trim();
        result.thinkingDone = false;
        originalMsg = originalMsg.substring(0, thinkOpenIndex).trim();
      } else {
        // 检查是否有不完整的开始标签（如<think、<th等）
        const partialOpenTagRegex = /<th(?:ink)?(?!\w)/i;
        const partialOpenMatch = originalMsg.match(partialOpenTagRegex);
        
        if (partialOpenMatch) {
          // 找到了不完整的开始标签，从该位置开始的内容都应该被当作思考内容的一部分
          const partialIndex = originalMsg.indexOf(partialOpenMatch[0]);
          // 将整个不完整标签及后续内容都视为思考内容的一部分
          // 但此时将其作为content的一部分，等待完整标签出现时再处理
          originalMsg = originalMsg.substring(0, partialIndex).trim();
        }
      }
    }
    
    // 去除任何可能残留的不完整标签
    originalMsg = originalMsg
      .replace(/<\/?th(?:ink)?(?!\w)[^>]*>/gi, '') // 移除任何不完整的开始或结束标签
      .replace(/<think>/g, '')
      .replace(/<\/think>/g, '');
    
    result.content = originalMsg.trim();
    
  } catch (e) {
    console.error('解析AI消息失败:', e);
  }
  
  return result;
}

const watchMessage = (): void => {
  if (message.value) {
    const lastIndex = historyMessages.value.length - 1;
    if (lastIndex >= 0 && historyMessages.value[lastIndex].type === 'ai') {
      const lastAIMessage = historyMessages.value[lastIndex];
      
      const parsedMessage = parseAIMessage(message.value);
      
      // 注意：参考资料现在从搜索API获取，不再从AI响应中解析
      
      const hasThinkStartTag = message.value.includes('<think>');
      const hasThinkEndTag = message.value.includes('</think>');
      
      if (hasThinkStartTag && parsedMessage.thinking.trim() !== '') {
        if (!lastAIMessage.hasThinking) {
          const thinkingMessage: Extract<MessageType, { hasThinking: true }> = {
            ...lastAIMessage,
            hasThinking: true,
            thinking: {
              content: parsedMessage.thinking,
              done: hasThinkEndTag,
              time: 0,
              startTime: Date.now()
            }
          };
          
          historyMessages.value[lastIndex] = thinkingMessage;
        } else {
          const thinkingMessage = lastAIMessage as Extract<MessageType, { hasThinking: true }>;
          thinkingMessage.thinking.content = parsedMessage.thinking;
          
          if (hasThinkEndTag && !thinkingMessage.thinking.done) {
            thinkingMessage.thinking.done = true;
            
            if (thinkingMessage.thinking.startTime) {
              const elapsedTime = Date.now() - thinkingMessage.thinking.startTime;
              thinkingMessage.thinking.time = Math.max(1, Math.round(elapsedTime / 1000));
            } else {
              thinkingMessage.thinking.time = 3; 
            }
          }
        }
      } else if (!hasThinkStartTag && lastAIMessage.hasThinking) {
        const nonThinkingMessage: Extract<MessageType, { hasThinking?: false }> = {
          ...lastAIMessage,
          hasThinking: false,
          thinking: undefined
        };
        
        historyMessages.value[lastIndex] = nonThinkingMessage;
      }
      
      if (!hasThinkStartTag || hasThinkEndTag) {
        historyMessages.value[lastIndex].content = parsedMessage.content;
      }
      
      chatStore.saveSearchMessages(sessionId.value, historyMessages.value)
      
      if (shouldAutoScroll.value && !isUserScrolling.value) {
        scrollToBottom();
      }
    }
  }
}

const watchError = (): void => {
  if (error.value) {
    showToast(error.value)
    setTimeout(() => {
      chatStore.connectionState.error = ''
    }, 100)
  }
}

onMounted(() => {
  if (chatContent.value) {
    chatContent.value.addEventListener('scroll', handleScroll)
  }
})

onBeforeUnmount(() => {
  if (chatContent.value) {
    chatContent.value.removeEventListener('scroll', handleScroll)
  }
  if (scrollTimer.value) {
    clearTimeout(scrollTimer.value)
  }
})

watch(message, () => {
  watchMessage();
});

watch(error, (newVal) => {
  if (newVal) {
    watchError()
  }
})
watch(loading, (newVal: boolean, oldVal: boolean) => {
  if (newVal === false && oldVal === true) {
    shouldAutoScroll.value = true
  }
})

const showReferences = ref(false)
const selectedReference = ref<any>(null)
const selectedReferences = ref<any[]>([]);

const openReferences = (references: any[]) => {
  selectedReferences.value = references;
  showReferences.value = true;
}

const selectReference = (ref: any) => {
  selectedReference.value = ref
  showDialog({
    title: '您即将离开witdata，跳转到第三方网站',
    message: 'witdata出于为您提供便利的目的向您提供第三方链接，我们不对第三方网站的内容负责，请您审慎访问，保护好您的信息及财产安全。',
    showCancelButton: true,
    cancelButtonText: '取消',
    confirmButtonText: '继续访问',
    confirmButtonColor: '#4080ff',
  }).then(() => {
    window.open(ref.url, '_blank');
    showReferences.value = false;
  }).catch(() => {
  })
}
</script>

<template>
  <div class="ai-search-container" :class="{ embed: props.embed }">
    <div class="web-header">
      <div class="title">AI搜索</div>
      <div class="actions">
        <div class="clear-button" @click="clearHistory">
          <Icon name="delete-o" size="16" />
          <span>清空会话</span>
        </div>
      </div>
    </div>
    <div class="chat-content" ref="chatContent">
      <WelcomeMessage v-if="historyMessages.length === 0" />
      <MessageList
        v-else
        :messages="historyMessages"
        :loading="loading"
        @open-references="openReferences"
      />
    </div>
    <SearchInput
      :loading="loading"
      @search="handleSearch"
      @stop="handleStopStream"
    />
    <ReferenceMaterial
      :show="showReferences"
      @update:show="showReferences = $event"
      :references="selectedReferences"
      @select="selectReference"
      :embed="props.embed"
    />
  </div>
</template>

<style lang="scss" scoped>
.ai-search-container {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 600px;
  background-color: #fff;
  position: relative;
  border-radius: 8px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
  width: 100%;
  max-width: 100%;
  margin: 0;

  .web-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 24px;
    border-bottom: 1px solid #ebeef5;
    background-color: #fff;
    position: fixed;
    top: 60px;
    left: 0;
    right: 0;
    z-index: 100;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
    
    .title {
      font-size: 18px;
      font-weight: 500;
      color: #333;
    }
    .actions {
      .clear-button {
        display: flex;
        align-items: center;
        gap: 6px;
        padding: 8px 16px;
        background-color: #f5f5f5;
        border-radius: 4px;
        color: #606266;
        font-size: 14px;
        cursor: pointer;
        transition: all 0.2s;
        
        &:hover {
          background-color: #e8e8e8;
        } 
      }
    }
  }
  .chat-content {  
    flex: 1;
    overflow-y: auto;
    padding: 24px;
    margin-top: 60px;
    padding-bottom: 80px;
    background-color: #f7f8fa;
    
    &::-webkit-scrollbar {
      width: 6px;
    }
    
    &::-webkit-scrollbar-thumb {
      background-color: #c0c4cc;
      border-radius: 3px;
    }
    
    &::-webkit-scrollbar-track {
      background-color: #f5f7fa;
    }
  }
  &.embed {
    .web-header {
      position: static !important;
      width: 100% !important;
      box-shadow: none;
      border-radius: 0;
      top: 0;
      left: 0;
      right: 0;
      z-index: auto;
    }
    .chat-content {
      margin-top: 0 !important;
      padding-bottom: 80px;
    }
    .input-area {
      position: static !important;
      width: 100% !important;
      left: 0;
      right: 0;
      bottom: 0;
      z-index: auto;
    }
  }
}

@keyframes fadeIn {
  from { opacity: 0.7; }
  to { opacity: 1; }
}
</style>
